package com.charles.aspect;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.charles.annotations.SignatureValidation;
import com.charles.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;

/**
 * 统一验签：
 * 请求 json 添加 appSecret 字段，md5 加密后，丢到 sign 里，appSecret 不传，sign 必传
 *
 * @author jason
 */
@Slf4j
@Aspect
public class SignAspect {

    @Before("@annotation(signatureValidation)")
    public void doBefore(SignatureValidation signatureValidation) throws Throwable {
        // 接收到请求，记录请求内容
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        SortedMap<String, String> allParams = HttpUtils.getAllParams(request);

        // 1、获取请求sign签名参数，
        String sign = allParams.get("sign");
        if (StrUtil.isBlank(sign)) {
            throw new RuntimeException("sign不能为空");
        }
        // 2、获取请求参数secret
        String appId = allParams.get("appId");
        String appSecret = getAppSecret(appId);
        if (StrUtil.isBlank(appSecret)) {
            throw new RuntimeException("appId不合法");
        }
        // 3、获取请求参数timestamp 时间戳，
        String timestamp = allParams.get("timestamp");
        if (StrUtil.isBlank(timestamp)) {
            throw new RuntimeException("timestamp不能为空");
        }
        //3. 比较时间，120s内为合法请求
        if (Math.abs(Long.parseLong(timestamp) - System.currentTimeMillis()) > 120000) {
            throw new RuntimeException("timestamp失效");
        }
        allParams.put("secret", appSecret);
        verifySign(allParams);
    }

    private void verifySign(SortedMap<String, String> allParams) {
        // 对方签名
        String sign = allParams.get("sign");
        allParams.remove("sign");
        String mySign = SecureUtil.md5(JSONUtil.toJsonStr(allParams)).toUpperCase();

        log.info("验签，对方签名：{}，我方签名：{}", sign, mySign);
        // 验签
        Assert.isTrue(StrUtil.equals(sign, mySign), "验签失败");
    }

    public String getAppSecret(String appId) {
        Map<String, String> map = new HashMap<>();

        map.put("zs001", "asd123fhg3b7fgh7dfg");
        map.put("ls001", "hghfgh123btgfyh1212");

        return map.get(appId);
    }

}

